#include "Dosing_Pump.h";

extern LiquidCrystal     lcd;
extern Clock                           clock;
extern Alerts                        alerts;

void  Dosing_Pump::init(byte _PumpNum,int _Pump_Pin_Num,int _Stirrer_Pin_Num){
  int address = EEPROM_DOSING_PUMP_ADDRESS_START + (EEPROM_DOSING_PUMP_ADDRESS_OFFSET* _PumpNum) ;
 
  PumpNum = _PumpNum;
  Pump_Pin_Num         = _Pump_Pin_Num;
  Stirrer_Pin_Num = _Stirrer_Pin_Num;
  
  pinMode(Pump_Pin_Num, OUTPUT);
  pinMode(Stirrer_Pin_Num, OUTPUT);
 
  Day = 0; // Not need to save this on the EEPROM
  Pump_Calibration_ask = 0; // Not need tosave this on the EEPROM
  Pump_Calibration_in = 0; // Not need tosave this on the EEPROM
  MoreThenMax = false;// Not need tosave this on the EEPROM
  TimeNotRun = false;// Not need tosave this on the EEPROM
  
  Pump_mode= EEPROM.read(address++) ;
  Stirrer_Time = EEPROM.read(address++) ;

  byte b[sizeof(unsigned long)];
  for(int i = 0 ; i < sizeof(unsigned long) ; ++i ){
    b[i] = EEPROM.read(address++) ;
  }
  for(int i = 0 ; i < sizeof(unsigned long) ; ++i ){
    Pump_ml2time = Pump_ml2time << 8;
    Pump_ml2time += b[sizeof(unsigned long) - i-1]     ;
  }

  Alert= EEPROM.read(address++) ;

  Clear_history_ask = false; // Not need tosave this on the EEPROM
  History = 0;// Not need tosave this on the EEPROM
  History_l = 0;// Not need tosave this on the EEPROM
  Pump_Liquid_Amount_l_last_time = 0;// Not need tosave this on the EEPROM
  Pump_Liquid_Amount_h_last_time = 0;// Not need tosave this on the EEPROM

  for ( int i = 0 ; i < DOSING_PUMP_NUMBER_OF_PROGRAMS ; ++ i ) {
    Program_Mode[i] = EEPROM.read(address++) ;
    Program_Days[i] = EEPROM.read(address++) ;
    Start_Pump_HR[i] = EEPROM.read(address++) ;
    Start_Pump_MIN[i] = EEPROM.read(address++) ;
    Pump_Liquid_Amount_l[i] = EEPROM.read(address++) ;
    Pump_Liquid_Amount_h[i] = EEPROM.read(address++) ;
  }
  Stirrer_Speed = EEPROM.read(address++) ; 
}

void Dosing_Pump::Save_To_EEPROM(){
  int address = EEPROM_DOSING_PUMP_ADDRESS_START + (EEPROM_DOSING_PUMP_ADDRESS_OFFSET* PumpNum) ;

  EEPROM.write(address++,Pump_mode ) ;
  EEPROM.write(address++,Stirrer_Time ) ;
  unsigned long temp =  Pump_ml2time;
  for(int i = 0 ; i < sizeof(unsigned long) ; ++i ){    
    byte b = lowByte(temp);
    temp = temp >> 8;
    EEPROM.write(address++,b ) ;
  }
  EEPROM.write(address++,Alert ) ;

  for ( int i = 0 ; i < DOSING_PUMP_NUMBER_OF_PROGRAMS ; ++ i ) {
    EEPROM.write(address++,Program_Mode[i] ) ;
    EEPROM.write(address++,Program_Days[i] ) ;
    EEPROM.write(address++,Start_Pump_HR[i] ) ;
    EEPROM.write(address++,Start_Pump_MIN[i] ) ;
    EEPROM.write(address++,Pump_Liquid_Amount_l[i] ) ;
    EEPROM.write(address++,Pump_Liquid_Amount_h[i]  ) ;
  }

   EEPROM.write(address++,Stirrer_Speed ) ;
}

void  Dosing_Pump::Turn_Stirrer_On(){    // Tuen the Stirrer on
  if (Stirrer_Start_Time > 0 )
   analogWrite(Stirrer_Pin_Num, 255);
  else
      analogWrite(Stirrer_Pin_Num, Stirrer_Speed);
  //digitalWrite(Stirrer_Pin_Num, HIGH);  
}

void  Dosing_Pump::Turn_Stirrer_Off(){     // Tuen the Stirrer off
 analogWrite(Stirrer_Pin_Num, 0);
 //digitalWrite(Stirrer_Pin_Num, LOW);  
}

void  Dosing_Pump::Turn_Pump_On(){  // Tuen the Pump on
  digitalWrite(Pump_Pin_Num, HIGH);  
}

void  Dosing_Pump::Turn_Pump_Off(){  // Tuen the Pump off
  digitalWrite(Pump_Pin_Num, LOW);  
}

void Dosing_Pump::Check_Alert(){

  if (  Alert != 0 && ( History > ( ( (int) Alert ) * 10 )  ) ){
    alerts.Set_Dosing_Pump_Alert(PumpNum);
  }
}

void Dosing_Pump::Start(byte _Stirrer_Time , byte _Pump_Liquid_Amount_l ,   byte _Pump_Liquid_Amount_h){
  History += _Pump_Liquid_Amount_h;
  History_l+= _Pump_Liquid_Amount_l;
  if ( History_l >= 100){
    History_l -= 100;
    ++History;
  }
  Check_Alert();
  Pump_Liquid_Amount_l_last_time =  _Pump_Liquid_Amount_l;
  Pump_Liquid_Amount_h_last_time =  _Pump_Liquid_Amount_h;
  //Serial << "Start Stirrer " <<  (int) _Stirrer_Time << " Pump_Liquid_Amount "<<  Get_Liquid_Amount(_Pump_Liquid_Amount_l ,  _Pump_Liquid_Amount_h)  << endl ;

  Last_time_update =  millis() ;
  if ( _Stirrer_Time > 0 ){
    Stirrer_Run_Time += _Stirrer_Time;
    Stirrer_Start_Time = 3;
  }
  Pump_Run_Time += (Pump_ml2time *  (unsigned long )_Pump_Liquid_Amount_h);
  Pump_Run_Time +=  (Pump_ml2time *  (unsigned long )_Pump_Liquid_Amount_l)/100;

}

void Dosing_Pump::update( bool new_min,bool new_sec){
  unsigned long cur_time = millis();
  if ( MoreThenMax || TimeNotRun ){
    Turn_Stirrer_Off();     // Tuen the Stirrer off
    Turn_Pump_Off(); 
  }else{
    if ( Stirrer_Run_Time == 0 ) {
      Turn_Stirrer_Off();     // Tuen the Stirrer off
      if ( Pump_Run_Time > 0 ) {
        Turn_Pump_On();  // Tuen the Pump on  
        if (    (  cur_time - Last_time_update)  >= Pump_Run_Time ){
          Pump_Run_Time = 0;
        }
        else{
          Pump_Run_Time -=  ( cur_time  - Last_time_update) ;
        }
      } 
      else {
        if ( !Pump_Calibration_in){
          Turn_Pump_Off(); 
        }
      }
    }
    else {
      Turn_Stirrer_On();
      Turn_Pump_Off(); 
      if ( new_sec & Stirrer_Start_Time > 0){
        --Stirrer_Start_Time;
      } 
      if ( ( Stirrer_Run_Time > 0 ) & new_min ) {
        --Stirrer_Run_Time;
      }
    }
  }
  if ((Pump_Run_Time > 50000) && (PumpNum == 0) ){
    MoreThenMax = true;
    alerts.Set_Dosing_Pump_Alert(PumpNum);
  }
  if ((Pump_Run_Time > 10000) && (PumpNum != 0) ){
    MoreThenMax = true;
    alerts.Set_Dosing_Pump_Alert(PumpNum);
  }
  if (Last_time_update ==   cur_time ) {
    TimeNotRun = true;
    alerts.Set_Dosing_Pump_Alert(PumpNum);
  }
  Last_time_update =   cur_time ;
}

bool Dosing_Pump::Check_Program_day(byte Cur_Day,byte program_num){
  return  bitRead(Program_Days[program_num] , Cur_Day ) == 1;
}

void Dosing_Pump::Cheange_Program_day(byte Day,byte program_num){
  bitWrite(Program_Days[program_num], Day,  !bitRead(Program_Days[program_num] , Day )  );   
}

void Dosing_Pump::Check_Pump_programs(){
  byte Cur_Day = clock.get_day();
  byte Cur_Hr = clock.get_hr();
  byte Cur_Min = clock.get_min();

  for ( byte program_num = 0 ; program_num <  DOSING_PUMP_NUMBER_OF_PROGRAMS ; ++program_num){
    if ( Program_Mode[program_num] ){
      if ( Check_Program_day(Cur_Day , program_num)  ) {
        if (   ( Cur_Hr == Start_Pump_HR[ program_num] )  &&  ( Cur_Min == Start_Pump_MIN[ program_num] )  ){
          Start(Stirrer_Time ,Pump_Liquid_Amount_l[ program_num] ,  Pump_Liquid_Amount_h[ program_num]);
        }       
      }
    }
  }
}

void Dosing_Pump::Print_Last_Time(){
  lcd.print("Last Time : ");
  lcd.print(  Get_Liquid_Amount(Pump_Liquid_Amount_l_last_time , Pump_Liquid_Amount_h_last_time)    );
  lcd.print("ml"); 
}

void Dosing_Pump::Print_History(){
  lcd.print("Total : ");
  lcd.print(History );
  lcd.print(".");
  lcd.print((int)History_l);

  lcd.print("ml"); 
}

void Dosing_Pump::Clear_History(){
  History = 0;
  History_l= 0;
  Pump_Liquid_Amount_l_last_time =  0;
  Pump_Liquid_Amount_h_last_time =  0;
}

float Dosing_Pump::Get_Liquid_Amount(byte _Pump_Liquid_Amount_l ,   byte _Pump_Liquid_Amount_h){
  float temp = ( (float)_Pump_Liquid_Amount_l) / 100;
  temp += _Pump_Liquid_Amount_h;
  return temp;
}

float Dosing_Pump::Get_Liquid_Amount(byte program_num){
  return Get_Liquid_Amount(Pump_Liquid_Amount_l[program_num] ,   Pump_Liquid_Amount_h[program_num]);
}

void Dosing_Pump::Print_Liquid(byte _Pump_Liquid_Amount_l ,   byte _Pump_Liquid_Amount_h){
  strcpy_P(buffer, (char*)pgm_read_word(&(  gen_string_table[ Liquid_STRING  ]     )));
  lcd.print(buffer );
  lcd.print(  Get_Liquid_Amount(_Pump_Liquid_Amount_l ,  _Pump_Liquid_Amount_h)    );
  lcd.print("ml"); 
}

void Dosing_Pump::Print_Liquid(byte program_num){
  Print_Liquid(Pump_Liquid_Amount_l[program_num] ,   Pump_Liquid_Amount_h[program_num]);
}

void  Dosing_Pump::Start_Pump_Calibration(){
  Pump_Calibration_in = true;
  Calibration_Start_Time = millis();
  Turn_Pump_On();
}
void  Dosing_Pump::End_Pump_Calibration(){
  Pump_ml2time =  ( millis() - Calibration_Start_Time )  / DOSING_PUMP_CALIBRATION_AMOUNT;
   Turn_Pump_Off();
   Pump_Calibration_in = false;
   Save_To_EEPROM();
}

bool Dosing_Pump::Key_Prass_Gen(byte index,char Key){
  if ( Pump_Calibration_ask ){
    if ( Key == '1') { // Yes
      Pump_Calibration_ask = false;
       return true;
    }
    if ( Key == '3' ){ // No
      Pump_Calibration_ask = false;
    }  
  }
  else {
    switch (index){
    case 0:
      if ( Key == '6') {
        Pump_mode = true;        
      }
      if ( Key == '4' ){
        Pump_mode = false;
      }  
      break;
    case 1:
      if ( Key == '6') {
        if ( Stirrer_Time < 255 ) {
          ++Stirrer_Time;
        }
      }
      if ( Key == '4' ){
        if ( Stirrer_Time > 0 ) {
          --Stirrer_Time;
        }
      }  
      break;
    case 2:
      if ( Key == '6') {
        if ( Stirrer_Speed < 255 ) {
          ++Stirrer_Speed;
        }
      }
      if ( Key == '3') {
        if ( Stirrer_Speed < 246 ) {
          Stirrer_Speed += 10;
        }
      }
      if ( Key == '4' ){
        if ( Stirrer_Speed > 0 ) {
          --Stirrer_Speed;
        }
      }  
      if ( Key == '1' ){
        if ( Stirrer_Speed > 9 ) {
          Stirrer_Speed -= 10;
        }
      }  
      break;
    case 3:
      if ( Key == '6') {
        if ( Alert < 255 ) {
          ++Alert;
        }
      }
      if ( Key == '4' ){
        if ( Alert > 0 ) {
          --Alert;
        }
      }  
      break;
    case 4:
      if ( Key == '5' ){
        Pump_Calibration_ask = true;
      }
      break;
    }
  }
  return false;
}

bool Dosing_Pump::Print_promt_Gen(){
  if ( Pump_Calibration_ask || Pump_Calibration_in ){
    return false;
  }
  return true;
}

void Dosing_Pump::Print_Gen(byte index){
  if ( Pump_Calibration_ask ){
    if ( (index % 4) == 3 ) {
     lcd.setCursor(0, 0);
     lcd.print("Start Calibration");
     lcd.setCursor(0, 1);
     strcpy_P(buffer, (char*)pgm_read_word(&(  gen_string_table[ YES_NO_STRING  ]     )));
     lcd.print(buffer );
    }
      /*
    switch (index){
    case 0:
      lcd.print("Start Calibration");
      break;
    case 1:
      strcpy_P(buffer, (char*)pgm_read_word(&(  gen_string_table[ YES_NO_STRING  ]     )));
      lcd.print(buffer );
      break;
    }
    */
  }  
  else {
    switch (index){
    case 0:
      lcd.print("Pump Mode :");
      if ( Pump_mode  == false){
        Print_OFF();
      } 
      else {
        Print_ON();
      }  
      break;
    case 1:
      strcpy_P(buffer, (char*)pgm_read_word(&(  gen_string_table[  STIRRER_TIME_STRING ]     )));
      lcd.print(buffer );
      if ( Stirrer_Time ==  0 ){
        Print_OFF();
      } 
      else {
        lcd.print((int)Stirrer_Time);
      }  
      break;
     case 2:
            lcd.print("Stirrer Speed: ");
            lcd.print((int)Stirrer_Speed);  
      break;
    case 3:
      lcd.print("Alert : ");
      if ( Alert == 0){
        Print_OFF();
      }
      else {
        lcd.print( ((int)Alert)*10 );
        lcd.print( "ml" );
      }
      break;
    case 4:
      lcd.print("Pump Calibration");
      break;
    case 5:
      if (  MoreThenMax ){
        lcd.print("MoreThenMax");
      }else if  ( TimeNotRun) {
        lcd.print("TimeNotRun");
      }else {
        lcd.print(Pump_ml2time);
        lcd.print(" millis/ml");
      }
      break;
    }
  }
} 


void Dosing_Pump::Key_Prass_Set(byte index,char Key){
  byte  program_num = (index/4);
  byte  offset = (index%4);
  if ( offset != 3) Day = 1;
  switch (offset){
  case 0:
    if ( Key == '6') {
      Program_Mode[program_num] = true;
    }
    if ( Key == '4' ){
      Program_Mode[program_num]  = false;
    }  
    break;
  case 1:
    if ( Key == '6') {
      Start_Pump_MIN[program_num]  = (Start_Pump_MIN[program_num]+ 1) %60;
    }
    if ( Key == '4' ){
      if ( Start_Pump_MIN[program_num] == 0  ) {
        Start_Pump_MIN[program_num]= 59;
      }
      else { 
        --Start_Pump_MIN[program_num] ;
      }
    }  
    if ( Key == '3') {
      Start_Pump_HR[program_num]  = (Start_Pump_HR[program_num]  +1 ) %24;
    }
    if ( Key == '1' ){
      if ( Start_Pump_HR[program_num] == 0 ){
        Start_Pump_HR[program_num]  = 23;
      } 
      else { 
        --Start_Pump_HR[program_num] ;
      }
    }  
    break;
  case 2:
    if ( Key == '6') {
      if ( Pump_Liquid_Amount_l[program_num]  < 90 ){
        Pump_Liquid_Amount_l[program_num] += 10;
      }
      else{
        Pump_Liquid_Amount_l[program_num] = 0;
        Pump_Liquid_Amount_h[program_num] += 1;
      }
    }

    if ( Key == '4') {
      if ( Pump_Liquid_Amount_l[program_num]  != 0 ){
        Pump_Liquid_Amount_l[program_num] -= 10;
      }
      else if ( Pump_Liquid_Amount_h > 0 ){
        Pump_Liquid_Amount_l[program_num] = 90;
        Pump_Liquid_Amount_h[program_num] -= 1;
      }
    }

    break;
  case 3:
    if ( Key == '6') {
      if (Day < 7 ){
        ++Day;
      } 
      else {
        Day = 1;
      }
    }
    if ( Key == '4') {
      Cheange_Program_day(Day,program_num);
    }
    break;
  }
}

void Dosing_Pump::Print_Set(byte index){
  byte  program_num = (index/4);
  byte  offset = (index%4);
  switch (offset){
  case 0:
    lcd.print("Program");
    lcd.print((int)program_num + 1);
    lcd.print(" Mode :");
    if ( Program_Mode[program_num]  == false){
      Print_OFF();
    } 
    else {
      Print_ON();
    }  
    break;
  case 1:
    lcd.print(" Start Time : ");
    clock.print_time_min(Start_Pump_HR[program_num ],Start_Pump_MIN[program_num ]);  
    break;
  case 2:
    Print_Space();
    Print_Liquid(program_num);
    break;
  case 3:
    lcd.print(" Days:");
    for ( int day = 1 ; day < 8 ; ++day){
      if ( Check_Program_day(day,program_num) ){
        strcpy_P(buffer, (char*)pgm_read_word(&(  short_days_names_table[ day -1 ]     )));
        lcd.print(buffer );
      }
      else{
        if( day != 7 ){
          Print_Space();  
        }
      }
    } 
    break;
  }
} 




























































